package com.bestcem.xm.txtanls.grpc.service;

import cn.hutool.core.collection.CollUtil;
import com.bestcem.xm.common.core.domain.web.RpcStatusResult;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.uitls.GRpcUtil;
import com.bestcem.xm.txtanls.grpc.convert.ChartConvert;
import com.bestcem.xm.txtanls.grpc.convert.TopicConvert;
import com.bestcem.xm.txtanls.grpc.service.param.topic.*;
import com.bestcem.xm.txtanls.grpc.v1.services.*;
import com.bestcem.xm.txtanls.service.TopicService;
import com.bestcem.xm.txtanls.service.dto.chart.PeriodTimeDTO;
import com.bestcem.xm.txtanls.service.dto.chart.TimeRangeDTO;
import com.bestcem.xm.txtanls.service.dto.topic.TopicDTO;
import com.bestcem.xm.txtanls.service.dto.topic.TopicDataDTO;
import com.bestcem.xm.txtanls.service.dto.topic.TopicGroupDTO;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static com.bestcem.xm.common.core.constant.Constants.DEFAULT_ARRAY_SIZE;

/**
 * @author liheng
 * @version v1.0
 * @date 2021/6/21 19:05
 */
@Slf4j
@GrpcService
public class TopicGrpcService extends TopicServiceGrpc.TopicServiceImplBase {

    @Resource
    private TopicService topicService;


    /**
     * 创建话题/组
     *
     * @param request
     * @param responseObserver
     * @author liheng
     * @date 2021/5/20 17:32
     */
    @Override
    public void createTopic(CreateTopicRequest request, StreamObserver<CreateTopicResponse> responseObserver) {
        CreateTopicParam createTopicParam = new CreateTopicParam(request.getTypeValue(), request.getName(), request.getProjectId(), request.getTopicGid());
        CreateTopicResponse.Builder builder = CreateTopicResponse.newBuilder();
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(createTopicParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<String> result = topicService.saveTopic(createTopicParam);
        if (result.isSuccess()) {
            builder.setId(result.getData());
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 修改名称或关键词
     *
     * @param request
     * @param responseObserver
     * @author liheng
     * @date 2021/5/21 10:13
     */
    @Override
    public void updateTopic(UpdateTopicRequest request, StreamObserver<CreateTopicResponse> responseObserver) {
        UpdateTopicParam updateTopicParam = new UpdateTopicParam(request.getId(), request.getProjectId(), request.getName(), request.getKeyDictList(), request.getUpdateKeywordFlag());
        CreateTopicResponse.Builder builder = CreateTopicResponse.newBuilder();

        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(updateTopicParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<String> result = topicService.updateTopic(updateTopicParam);

        if (result.isSuccess()) {
            builder.setId(result.getData());
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 移动话题
     *
     * @param request
     * @param responseObserver
     * @author liheng
     * @date 2021/5/21 10:13
     */
    @Override
    public void moveToAnotherGroup(MoveToAnotherGroupRequest request, StreamObserver<MoveToAnotherGroupResponse> responseObserver) {
        MoveTopicParam moveTopicParam = new MoveTopicParam(request.getId(), request.getProjectId(), request.getGroupName(), request.getTopicGid());
        MoveToAnotherGroupResponse.Builder builder = MoveToAnotherGroupResponse.newBuilder();

        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(moveTopicParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<String> result = topicService.moveTopic(moveTopicParam);
        if (result.isSuccess()) {
            builder.setId(result.getData());
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 删除话题/组
     *
     * @param request          request
     * @param responseObserver responseObserver
     * @author liheng
     * @date 2021/5/21 10:13
     */
    @Override
    public void deleteTopic(DeleteTopicRequest request, StreamObserver<DeleteTopicResponse> responseObserver) {
        DeleteTopicResponse.Builder builder = DeleteTopicResponse.newBuilder();
        if (ObjectUtils.isEmpty(request.getId()) || !ObjectId.isValid(request.getId())) {
            builder.setStatus(RpcStatusResult.error("话题id错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        ServiceResult<String> result = topicService.deleteTopic(request.getId());
        if (result.isSuccess()) {
            builder.setId(result.getData());
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 导出话题信息
     *
     * @param request
     * @param responseObserver
     * @author liheng
     * @date 2021/5/21 10:13
     */
    @Override
    public void exportTopic(ExportTopicRequest request, StreamObserver<ExportTopicResponse> responseObserver) {

        ExportTopicResponse.Builder builder = ExportTopicResponse.newBuilder();
        if (ObjectUtils.isEmpty(request.getProjectId()) || !ObjectId.isValid(request.getProjectId())) {
            builder.setStatus(RpcStatusResult.error("文本分析项目id错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<List<TopicDataDTO>> result = topicService.exportTopicData(request.getProjectId());
        if (result.isSuccess()) {
            builder.addAllTopics(this.changeDataDTO(result.getData()));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 导入话题信息
     *
     * @param request
     * @param responseObserver
     * @author liheng
     * @date 2021/5/21 10:13
     */
    @Override
    public void importTopic(ImportTopicRequest request, StreamObserver<ImportTopicResponse> responseObserver) {
        ImportTopicResponse.Builder builder = ImportTopicResponse.newBuilder();
        ImportTopicParam importTopicParam = new ImportTopicParam(request.getProjectId(), TopicConvert.changeImportData(request.getTopicsList()));
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(importTopicParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult result = topicService.importTopicData(importTopicParam);
        if (result.isSuccess()) {
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 话题组列表
     *
     * @param request
     * @param responseObserver
     * @author liheng
     * @date 2021/5/21 10:13
     */
    @Override
    public void listTopicGroup(ListTopicGroupRequest request, StreamObserver<ListTopicGroupResponse> responseObserver) {
        ListTopicGroupParam listTopicGroupParam = new ListTopicGroupParam(request.getProjectId(), ChartConvert.timeRangeToTimeRangeDTO(request.getTimeRange()), request.getFieldId());
        ListTopicGroupResponse.Builder builder = ListTopicGroupResponse.newBuilder();
        TimeRangeDTO timeRangeDTO = listTopicGroupParam.getTimeRangeDTO();
        PeriodTimeDTO periodTime = timeRangeDTO.getPeriodTime();
        if (Objects.nonNull(periodTime)) {
            LocalDateTime startTime = periodTime.getStartTime();
            LocalDateTime endTime = periodTime.getEndTime();
            if (Objects.nonNull(startTime) && Objects.nonNull(endTime) && startTime.isAfter(endTime)) {
                builder.setStatus(RpcStatusResult.error("时间区间开始时间不能大于结束时间"));
                responseObserver.onNext(builder.build());
                responseObserver.onCompleted();
                return;
            }
        }
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(listTopicGroupParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<List<TopicGroupDTO>> result = topicService.listGroupByProjectId(listTopicGroupParam);
        if (result.isSuccess()) {
            builder.addAllGroups(this.changeGroupList(result.getData()));
            builder.setStatus(RpcStatusResult.success());
        } else {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    private List<TopicGroup> changeGroupList(List<TopicGroupDTO> topicGroupDTOS) {
        List<TopicGroup> topicGroups = new ArrayList<>(DEFAULT_ARRAY_SIZE);
        for (TopicGroupDTO topicGroupDTO : topicGroupDTOS) {
            TopicGroup.Builder builder = TopicGroup.newBuilder();
            List<TopicCount> topicCounts = this.changeTopicCount(topicGroupDTO.getTopicDTOs());
            if (CollUtil.isNotEmpty(topicCounts)) {
                builder.addAllTopics(topicCounts);
            }
            if (StringUtils.isNotBlank(topicGroupDTO.getId())) {
                builder.setId(topicGroupDTO.getId());
            }
            if (StringUtils.isNotBlank(topicGroupDTO.getName())) {
                builder.setName(topicGroupDTO.getName());
            }
            TopicGroup topicGroup = builder.build();
            topicGroups.add(topicGroup);
        }
        return topicGroups;
    }

    private List<ExportOrImportTopic> changeDataDTO(List<TopicDataDTO> topicDataDTOS) {
        List<ExportOrImportTopic> exportOrImportTopics = new ArrayList<>(DEFAULT_ARRAY_SIZE);
        for (TopicDataDTO topicDataDTO : topicDataDTOS) {
            ExportOrImportTopic.Builder builder = ExportOrImportTopic.newBuilder();
            if (StringUtils.isNotBlank(topicDataDTO.getTopicGroupName())) {
                builder.setGroupName(topicDataDTO.getTopicGroupName());
            }
            if (StringUtils.isNotBlank(topicDataDTO.getTopicName())) {
                builder.setName(topicDataDTO.getTopicName());
            }
            if (StringUtils.isNotBlank(topicDataDTO.getKeyword())) {
                builder.setKeyword(topicDataDTO.getKeyword());
            }
            ExportOrImportTopic topicData = builder.build();
            exportOrImportTopics.add(topicData);
        }
        return exportOrImportTopics;
    }


    private List<TopicCount> changeTopicCount(List<TopicDTO> topicDTOs) {
        List<TopicCount> topicCounts = new ArrayList<>(DEFAULT_ARRAY_SIZE);
        for (TopicDTO topicDTO : topicDTOs) {
            TopicCount.Builder builder = TopicCount.newBuilder();
            if (Objects.nonNull(topicDTO.getCount())) {
                builder.setCount(topicDTO.getCount());
            }
            if (StringUtils.isNotBlank(topicDTO.getProjectId())) {
                builder.setProjectId(topicDTO.getProjectId());
            }
            builder.setTopic(TopicConvert.toTopic(topicDTO));
            TopicCount topicCount = builder.build();
            topicCounts.add(topicCount);
        }
        return topicCounts;

    }
}
